<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue</title>
</head>
<body>
<div id="app">
    <h1>A login: {{ $store.state.a.login }}</h1>
    <h1>B click: {{ $store.state.b.clicks }}</h1>
    <h1>Root click: {{ $store.state.clicks }}</h1>
    <button @click="loginA">A login</button>
    <button @click="addB">B click+</button>
    <button @click="addR">Root click+</button>
</div>

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3.5.1/dist/vuex.js"></script>
<script>
    // 一些大型的应用上，状态可能很多，如果全部有一个store管理，容易导致臃肿，
    // 因此vuex支持模块化， 模块化store支持树状多层级，下面演示两层级
    const moduleA = {
        // 不配置命名空间情况下，继承自父模块命名空间
        state: {
            login: false
        },
        mutations: {
            setLogin(state, login) {
                state.login = login
            }
        },
        getters: {
            isLogin: state => {
                return state.login;
            }
        }
    };
    const moduleB = {
        namespaced: true, // 子模块增加namespaced，相当于在父模块基础上嵌套命名空间
        state: {
            clicks: 0
        },
        mutations: {
            add(state, n=1) {
                state.clicks += n;
            },
        },
        getters: {
            // rootState是根模块的state
            // 注意：如果要使用rootState，必须下面这样写，rootState是第三个参数，不是随意写上就行，第二个是getters
            // 如果直接两个参数，state,rootState, 则实际上rootState是getters的引用，此时调用clicks导致stack溢出
            // 第四个参数事rootGetters，也是可选，完整的环境参数为(state, getters, rootState, rootGetters)
            clicks: (state, getters, rootState) => {
                console.log(getters, rootState, rootState.clicks);
                //  console.log('clicks => ', state.clicks, rootState.clicks);
                return state.clicks;
            }
        },
        actions: {
            addRoot({state, commit, rootState}) {
                console.log('addRoot => ', state.clicks, rootState.clicks);
                // 因为启用了命名空间，所以add方法只会触发当前模块的add方法
                commit('add', rootState.clicks);
            }
        }
    };

    const store = new Vuex.Store({
        namespaced: true, //默认不加namespaced属性，所有模块包括根都在全局命名空间下
        state: {
            clicks: 10
        },
        mutations: {
            add(state) {
                state.clicks ++;
            }
        },
        modules: {
            a: moduleA,
            b: moduleB
        }
    });

    let vm = new Vue({
        el: "#app",
        data: {
            count: 0,
            login: false
        },
        methods: {
            loginA() {
                this.$store.commit('setLogin', this.login = !this.login);
            },
            addB() {
                // 因为声明了命名空间，所以通过命名空间调用
                this.$store.dispatch('b/addRoot');
                // 启用命名空间的情况下，使用getters的具体方法的方式如下
                console.log(this.$store.getters['b/clicks']);
            },
            addR() {
                // 因为启用了命名空间，所以只会触发根的命名空间下的add方法
                this.$store.commit('add');
                // 如果要触发模块b下的add方法，则如下调用方式
                // this.$store.commit('b/add');
            }
        },
        store
    });
</script>
</body>
</html>
